/**
 * 
 * @Project HRL Simulation
 * @Date 20.06.2011
 * @Author Aebi Pascal, Kocher Marc, Sriranjan George
 * @School BFH-TI Biel, Projekt 1
 *
 */

package gui;

import elements.Load;
import exceptions.LoadListException;
import exceptions.ResourceException;
import gui.objects3D.World3D;
import gui.views.HRLMainFrame;
import gui.views.StatisticsFrame;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFileChooser;

import main.ControlCenter;

import utils.HRLFileFilter;
import utils.Prop;
import utils.StatisticsManager;


public class Model {

	private JFileChooser fileChooser;
	private Prop properties;
	private ControlCenter cc;
	private World3D world3D;
	private StatisticsManager statisticsManager;
	private File selectedFile;
	private String sSettings = "Settings";
	private String sViewer = "Viewer";
	private String sVersionInfo = "Version: Realease 1.0";
	private String[] sArrayLiftInitPosition = { "Top", "Middle", "Bottom" };
	private String[][] sArrayStrategies = {
			{"Random", "The random strategy determines all variable values randomly." +
					   "\nThe lifts always stay on their last position." +
					   "\nInput process: It selects randomly a place in one of the racks and one of the two possible input buffer of the selected rack." +
					   "\nOutput process: It selects randomly one of the two possible output buffers."},
			{"Successive L-R", "The successive left-right strategy fills the storage successive from the most left rack to the most right." +
					   "\nInput process: It selects the next place in the most left rack which has a free slot and the upper input buffer of the selected rack." +
					   "\nOutput process: It selects the lower buffer of the two possible output buffers."},
			{"Successive T-D", "The successive top-down strategy fills the storage from the first place in each rack to the last." +
					   "\nInput process: It selects the first place in each rack and then goes to the second place of each rack and so on." + 
					   "\nOutput process: It selects the lower buffer of the two possible output buffers."},
			{"Optimized", "The optimized strategy simulates the whole way for each place first and the decides which one is the shortest considering the standing and occupancy of lifts and buffers" +
					   "\nInput process: It simulates the way to each place and selects the one with the shortest route time" +
					   "\nOutput process: It selects the lower buffer of the two possible output buffers."}
			};
	private String[] sArrayTableHeaderManualLoads = {"Name", "Class of good", "State", "Arrival time"};
	private String[] sArrayTableHeaderStatistics = {"Resource name", "Average idle time", "Average wait time", "Average book time", "Number of entries"};
	private String[] sArrayLoadStates = {"IN", "OUT", "STORE"};
	private String[] sArrayAuthors = {
			"<html><b>George Sriranjan</b><br>Logic, Algorithm, Simulation</html>",
			"<html><b>Pascal Aebi</b><br>GUI, Logic, Algorithm, Simulation</html>",
			"<html><b>Marc Kocher</b><br>Useability, 3D-Simulation, Algorithm</html>"
			};
	private List<Load> alManualLoads;
	
	
	/**
	 * 
	 */
	public Model(){
		this.fileChooser = new JFileChooser();
		this.properties = new Prop();
		this.alManualLoads = new ArrayList<Load>();
	}
	
	
	/**
	 * 
	 */
	public void createControlCenter(){
		this.cc = new ControlCenter();
	}
	
	
	/**
	 * 
	 */
	public void createWorld3D() {
		this.world3D =  new World3D(this.cc);
	}
	
	
	/**
	 * 
	 */
	public void createStatisticsManager(StatisticsFrame jfStatistics){
		this.statisticsManager = new StatisticsManager(this.cc);
		jfStatistics.addStatisticsData(statisticsManager.collectData());
	}
	
	/**
	 * 
	 * @param jfHRL
	 */
	public void loadProperties(HRLMainFrame jfHRL) {
		this.fileChooser.setAcceptAllFileFilterUsed(false);
		this.fileChooser.addChoosableFileFilter(new HRLFileFilter());
		if(this.fileChooser.showOpenDialog(jfHRL) == JFileChooser.APPROVE_OPTION){
			// Get file from dialog
			this.selectedFile = this.fileChooser.getSelectedFile();
			// Make sure if file can be processed before proceeding
			if(this.selectedFile.canRead() && this.selectedFile.exists() && this.selectedFile != null){
				Prop.load(this.selectedFile);
			}
	    }
	}
	
	
	/**
	 * 
	 * @param jfHRL
	 */
	public void saveProperties(HRLMainFrame jfHRL) {
		HRLFileFilter hrlFileFilter = new HRLFileFilter();
		String fileExtension = "." + hrlFileFilter.getFileExtension();
		this.fileChooser.setAcceptAllFileFilterUsed(false);
		this.fileChooser.addChoosableFileFilter(hrlFileFilter);
		this.fileChooser.setSelectedFile(new File("properties" + fileExtension));
		
		if(this.fileChooser.showSaveDialog(jfHRL) == JFileChooser.APPROVE_OPTION){
			// Get file from dialog
			File file = this.fileChooser.getSelectedFile();
			
			// Get file path and name
			String filePath = file.getAbsolutePath();
			String fileName = file.getName();
			
			// Check for correct extension
			if(fileName.contains(fileExtension)){
				int fileLength = fileName.length();
				int beginIndex = fileLength-4;
				if(!fileName.substring(beginIndex, fileLength).equals(fileExtension)){
					filePath = filePath + fileExtension;
				}
			}
			else{
				filePath = filePath + fileExtension;
			}
			
			// Get actual file from dialog
			this.fileChooser.setSelectedFile(new File(filePath));
			file = this.fileChooser.getSelectedFile();
			
			// Store file in file system
			Prop.store(file);
		}
	}
	
	
	/**
	 * @throws LoadListException only outgoing not possible
	 * 
	 */
	public void generateLoads() throws LoadListException {
		if(Prop.getInt(Prop.RANDOM_LOADS) == 0){
			this.cc.addManualLoads(this.alManualLoads);
		}
		else{
			boolean in = true;
			boolean out = true;
			boolean store = true;
			
			if(Prop.getInt(Prop.IN_LOADS) == 0){
				in = false;
			}
			if(Prop.getInt(Prop.OUT_LOADS) == 0){
				out = false;
			}
			if(Prop.getInt(Prop.STORE_LOADS) == 0){
				store = false;
			}
			
			cc.generateRandomLoads(Prop.getInt(Prop.RANDOM_LOAD_NUMBER), in, out, store);
		}
	}
	
	
	/**
	 * 
	 * @param rowData
	 */
	public void addManualLoad(String[] rowData){
		String loadName = rowData[0];
		String loadClass = rowData[1];
		Load.STATE laodState = null;
		Integer loadEntryTime = Integer.parseInt(rowData[3]);
		
		if(rowData[2].equalsIgnoreCase(Load.STATE.IN.toString())){
			laodState = Load.STATE.IN;
		}
		else if(rowData[2].equalsIgnoreCase(Load.STATE.OUT.toString())){
			laodState = Load.STATE.OUT;
		}
		else if(rowData[2].equalsIgnoreCase(Load.STATE.STORE.toString())){
			laodState =  Load.STATE.STORE;
		}
		
		Load load = new Load(loadName, loadClass, laodState, loadEntryTime);
		
		//TODO: check when its allowed to add (-> output and multiple entries)
		for (Load l : this.alManualLoads) {
			if(l.equals(load)){
				
			}
		}
	}
	
	
	/**
	 * 
	 * @param index
	 */
	public void removeManualLoad(int index) {
		this.alManualLoads.remove(index);
	}
	
	
	/**
	 * 
	 */
	public void clearManualLoadsTable(){
		this.alManualLoads.clear();
	}
	
	
	/**
	 * 
	 * @throws LoadListException entry in list is corrupt
	 * @throws ResourceException Position not found
	 */
	public void scheduleLoads() throws LoadListException, ResourceException{
		this.cc.schedule();
	}
	
	
	/**
	 * 
	 */
	public void setStrategy() {
		if(Prop.getInt(Prop.STRATEGY) == 0){
			this.cc.createRandomStrategy();
		}
		else if(Prop.getInt(Prop.STRATEGY) == 1){
			this.cc.createSuccessiveLeftRightStrategy();
		}
		else if(Prop.getInt(Prop.STRATEGY) == 2){
			this.cc.createSuccessiveTopDownStrategy();
		}
		else if(Prop.getInt(Prop.STRATEGY) == 3){
			this.cc.createOptimizedStrategy();
		}
	}
	

	/**
	 * Calculates the rack number
	 * @param liftNumber the lift number
	 * @return the rack number
	 */
	public Integer calculateRackNumber(Integer liftNumber) {
		Integer rackNumber = liftNumber*2;
		return rackNumber;
	}
	
	
	/**
	 * Calculates the maximum number of loads which are possible to generate randomly
	 * @param rackNumber
	 * @param rackLength
	 * @param rackHeight
	 * @return the maximum possible number of loads
	 */
	public Integer calculateMaxRandomLoadNumber(Integer rackNumber, Integer rackLength, Integer rackHeight) {
		return rackNumber * rackLength * rackHeight;
	}
	
	
	/**
	 * 
	 * @param sliderValue
	 * @return max speed value - slider value
	 */
	public Integer convertSliderSpeeds(Integer sliderValue){
		int maxSpeedValue = 10;
		return maxSpeedValue-sliderValue;
	}
	
	
	/**
	 * 
	 * @param sliderValue
	 * @return slider value
	 */
	public Integer convertSimlationSpeed(Integer sliderValue){
		if(sliderValue < 5){
			sliderValue = 6 - sliderValue;
		}
		else{
			sliderValue -= 4;
		}
		return sliderValue;
	}
	
	
	// getter ---------------------------------------------------------
	
	/**
	 * 
	 */
	public String[] getsArrayLiftInitPosition() {
		return sArrayLiftInitPosition;
	}
	
	
	/**
	 * 
	 * @return sArrayStragegies
	 */
	public String[][] getStrategies() {
		return sArrayStrategies;
	}
	
	
	/**
	 * 
	 * @return the sArrayTableHeaderManualLoads
	 */
	public String[] getTableHeaderManualLoads() {
		return sArrayTableHeaderManualLoads;
	}
		
	
	/**
	 * @return the sArrayTableHeaderStatistics
	 */
	public String[] getTableHeaderStatistics() {
		return sArrayTableHeaderStatistics;
	}


	/**
	 * 
	 * @return the sArrayLoadStates
	 */
	public String[] getLoadStates() {
		return sArrayLoadStates;
	}
	
	
	/**
	 * 
	 * @return the alManualLoads
	 */
	public List<Load> getManualLoads() {
		return alManualLoads;
	}


	/**
	 * 
	 * @return the sSettings
	 */
	public String getStringSettings() {
		return sSettings;
	}


	/**
	 * 
	 * @return the sViewer
	 */
	public String getStringViewer() {
		return sViewer;
	}


	/**
	 * 
	 * @return the sVersionInfo
	 */
	public String getStringVersionInfo() {
		return sVersionInfo;
	}
	
	
	/**
	 * 
	 * @return the sArrayAuthors
	 */
	public String[] getAuthors() {
		return sArrayAuthors;
	}
	
	
	/**
	 * 
	 * @return properties
	 */
	public Prop getProperties() {
		return properties;
	}
	
	
	/**
	 * 
	 * @return the world3d
	 */
	public World3D getWorld3D() {
		return this.world3D;
	}
	
	
	/**
	 * 
	 * @return the statisticsManager
	 */
	public StatisticsManager getStatisticsManager() {
		return statisticsManager;
	}


	/**
	 * @return the selectedFile
	 */
	public File getSelectedFile() {
		return selectedFile;
	}
	
	
}
